home *** CD-ROM | disk | FTP | other *** search
/ .net 2002 March / DotNetMagazine-Issue107-Coverdisc-NET107-02-03-PCMac.bin / pc / PC Software / picks / HTTrack / httrack-3.22-3.exe / {app} / src / htsname.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-17  |  42.5 KB  |  1,268 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       savename routine (compute output filename)             */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsname.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htstools.h"
  43. #include "htsmd5.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <ctype.h>
  47. /* END specific definitions */
  48.  
  49. #undef test_flush
  50. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  51.  
  52. #define ADD_STANDARD_PATH \
  53.     {  /* ajout nom */\
  54.       char buff[HTS_URLMAXSIZE*2];\
  55.       buff[0]='\0';\
  56.       strncatbuff(buff,start_pos,(int) (nom_pos - start_pos));\
  57.       url_savename_addstr(save,buff);\
  58.     }
  59.  
  60. #define ADD_STANDARD_NAME(shortname) \
  61.     {  /* ajout nom */\
  62.       char buff[HTS_URLMAXSIZE*2];\
  63.       standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\
  64.       url_savename_addstr(save,buff);\
  65.     }
  66.  
  67.  
  68. /* Avoid stupid DOS system folders/file such as 'nul' */
  69. /* Based on linux/fs/umsdos/mangle.c */
  70. static const char *hts_tbdev[] =
  71. {
  72.     "/prn", "/con", "/aux", "/nul",
  73.     "/lpt1", "/lpt2", "/lpt3", "/lpt4",
  74.     "/com1", "/com2", "/com3", "/com4",
  75.     "/clock$",
  76.     "/emmxxxx0", "/xmsxxxx0", "/setverxx",
  77.     ""
  78. };
  79.  
  80.  
  81.  
  82. // forme le nom du fichier ‡ sauver (save) ‡ partir de fil et adr
  83. // systËme intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
  84. int url_savename(char* adr_complete,char* fil_complete,char* save,char* former_adr,char* former_fil,char* referer_adr,char* referer_fil,httrackp* opt,lien_url** liens,int lien_tot,lien_back* back,int back_max,cache_back* cache,hash_struct* hash,int ptr,int numero_passe) {
  85.   char newfil[HTS_URLMAXSIZE*2];   /* ="" */
  86.   char* fil;
  87.   char* adr;
  88.   char* print_adr;
  89.   char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL;  // Position nom et point
  90.   // pour changement d'extension ou de nom (content-disposition)
  91.   int ext_chg=0;
  92.   char ext[256];
  93.   int max_char=0;
  94.   //CLEAR
  95.   newfil[0]=ext[0]='\0';
  96.  
  97.   /* 8-3 ? */
  98.   switch(opt->savename_83) {
  99.   case 1:
  100.     max_char=8;
  101.     break;
  102.   case 2:
  103.     max_char=30;
  104.     break;
  105.   default:
  106.     max_char=8;
  107.     break;
  108.   }
  109.  
  110.   // effacer save
  111.   save[0]='\0';
  112.   // fil
  113.   fil = fil_complete;
  114.   // et adr (sauter user/pass)
  115.   // on prend le parti de mettre les fichiers avec login/pass au mÍme endroit que si ils
  116.   // Ètaient capturÈs sans ces paramËtres
  117.   // c'est pour cette raison qu'on ignore totalement adr_complete (mÍme pour la recherche en table de hachage)
  118.   adr=jump_identification(adr_complete);
  119.  
  120.   // ‡ afficher sans ftp://
  121.   print_adr=jump_protocol(adr);
  122.  
  123.   // court-circuit pour lien primaire
  124.   if (strnotempty(adr)==0) {
  125.     if (strcmp(fil,"primary")==0) {
  126.       strcatbuff(save,"primary.html");
  127.       return 0;
  128.     }
  129.   }
  130.  
  131.  
  132.   // vÈrifier que le nom n'a pas dÈja ÈtÈ calculÈ (si oui le renvoyer tel que)
  133.   // vÈrifier que le nom n'est pas dÈja pris...
  134.   // NOTE: si on cherche /toto/ et que /toto est trouvÈ on le prend (et rÈciproquqment) ** // **
  135.   if (liens!=NULL) { 
  136.     int i;
  137.  
  138. #if HTS_HASH
  139.     i=hash_read(hash,adr,fil_complete,1);      // recherche table 1 (adr+fil)
  140.     if (i>=0) {    // ok, trouvÈ
  141.       strcpybuff(save,liens[i]->sav);
  142.       return 0;
  143.     }
  144.     i=hash_read(hash,adr,fil_complete,2);      // recherche table 2 (former_adr+former_fil)
  145.     if (i>=0) {    // ok, trouvÈ
  146.       // copier location moved!
  147.       strcpybuff(adr_complete,liens[i]->adr);
  148.       strcpybuff(fil_complete,liens[i]->fil);
  149.       // et save
  150.       strcpybuff(save,liens[i]->sav);  // copier (formÈ ‡ partir du nouveau lien!)
  151.       return 0;
  152.     }
  153. #else
  154.     for(i=lien_tot-1;i>=0;i--) {        
  155. #if HTS_CASSE
  156.       if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  157. #else
  158.       if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  159. #endif
  160.       {    // ok c'est le mÍme lien, adresse dÈja dÈfinie
  161.         strcpybuff(save,liens[i]->sav);
  162.         return 0;
  163.       }
  164.       if (liens[i]->former_adr) {     // tester ancienne loc?
  165. #if HTS_CASSE
  166.         if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete)==0))
  167. #else
  168.         if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete)))
  169. #endif
  170.         {
  171.           // copier location moved!
  172.           strcpybuff(adr_complete,liens[i]->adr);
  173.           strcpybuff(fil_complete,liens[i]->fil);
  174.           // et save
  175.           strcpybuff(save,liens[i]->sav);  // copier (formÈ ‡ partir du nouveau lien!)
  176.           return 0;
  177.         }
  178.       }
  179.     }
  180. #endif
  181.  
  182.     // chercher sans / ou avec / dans former
  183.     {
  184.       char fil_complete_patche[HTS_URLMAXSIZE*2];
  185.       strcpybuff(fil_complete_patche,fil_complete);
  186.       // Version avec ou sans /
  187.       if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/')
  188.         fil_complete_patche[strlen(fil_complete_patche)-1]='\0';
  189.       else
  190.         strcatbuff(fil_complete_patche,"/");
  191. #if HTS_HASH
  192.       i=hash_read(hash,adr,fil_complete_patche,2);      // recherche table 2 (former_adr+former_fil)
  193.       if (i>=0) {
  194.         // Ècraser fil et adr (pas former_fil?????)
  195.         strcpybuff(adr_complete,liens[i]->adr);
  196.         strcpybuff(fil_complete,liens[i]->fil);
  197.         // Ècrire save
  198.         strcpybuff(save,liens[i]->sav);
  199.         return 0;
  200.       }
  201. #else
  202.       // mÍme boucle en gros
  203.       for(i=lien_tot-1;i>=0;i--) {        
  204.         if (liens[i]->former_adr) {    // former-adr?
  205. #if HTS_CASSE
  206.           if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete_patche)==0))
  207. #else
  208.           if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete_patche)))
  209. #endif
  210.           {    // ok c'est le mÍme lien, adresse dÈja dÈfinie
  211.             // Ècraser fil et adr (pas former_fil?????)
  212.             strcpybuff(adr_complete,liens[i]->adr);
  213.             strcpybuff(fil_complete,liens[i]->fil);
  214.             // Ècrire save
  215.             strcpybuff(save,liens[i]->sav);
  216.             return 0;
  217.           }
  218.         }
  219.       }
  220. #endif
  221.     }
  222.   }
  223.  
  224.   // vÈrifier la non prÈsence de paramËtres dans le nom de fichier
  225.   // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur)
  226.   // nÈanmoins, gardÈ pour vÈrifier la non duplication (voir aprËs)
  227.   {
  228.     char* a;
  229.     a=strchr(fil,'?');
  230.     if (a!=NULL) {
  231.       strncatbuff(newfil,fil,(int) (a - fil));
  232.     } else {
  233.       strcpybuff(newfil,fil);
  234.     }
  235.     fil=newfil;
  236.   }
  237.   // dÈcoder %
  238.   strcpybuff(fil,unescape_http(fil));
  239.   /*
  240.   {
  241.     char tempo[HTS_URLMAXSIZE*2];
  242.     int i,j=0;
  243.     for (i=0;i<(int) strlen(fil);i++) {
  244.       if (fil[i]=='%') {
  245.         i++;
  246.         tempo[j++]=(char) ehex(fil+i);
  247.         i++;    // sauter 2 caractËres finalement
  248.       } else
  249.         tempo[j++]=fil[i];
  250.     }
  251.     tempo[j++]='\0';
  252.     strcpybuff(fil,tempo);
  253.   }
  254.   */
  255.   
  256.   
  257.   /* replace shtml to html.. */
  258.   switch (ishtml(fil)) {       /* .html,.shtml,.. */
  259.   case 1:
  260.     if ( 
  261.       (strcmp(get_ext(fil),"html") != 0)
  262.       && (strcmp(get_ext(fil),"htm") != 0)
  263.       ) {
  264.       strcpybuff(ext,"html");
  265.       ext_chg=1;
  266.     }
  267.     break;
  268.     case 0:
  269.       if (!strnotempty(ext)) {
  270.         if (is_userknowntype(get_ext(fil))) {      // mime known by user
  271.           char mime[1024];
  272.           mime[0]=ext[0]='\0';
  273.           get_userhttptype(0,mime,get_ext(fil));
  274.           if (strnotempty(mime)) {
  275.             give_mimext(ext,mime);
  276.             if (strnotempty(ext)) {
  277.               ext_chg=1;
  278.             }
  279.           }
  280.         }
  281.       }
  282.       break;
  283.   }
  284.   
  285.  
  286.   // si option check_type activÈe
  287.   if ((opt->check_type) && (!ext_chg)) {
  288.     int ishtest;
  289.     if ( (!strfield(adr_complete,"file://")) 
  290.       && (!strfield(adr_complete,"ftp://")) 
  291.       ) {
  292.       // tester type avec requËte HEAD si on ne connait pas le type du fichier
  293.       if (!(   (opt->check_type==1) && (fil[strlen(fil)-1]=='/')   ))    // slash doit Ítre html?
  294.       if ((ishtest=ishtml(fil)) < 0) { // on ne sait pas si c'est un html ou un fichier..
  295.         // lire dans le cache
  296.         htsblk r = cache_read(opt,cache,adr,fil,NULL);              // test uniquement
  297.         if (r.statuscode != -1) {  // pas d'erreur de lecture cache
  298.           char s[16]; s[0]='\0';
  299.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  300.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete);
  301.             test_flush;
  302.           }
  303.           if (strnotempty(r.cdispo)) {        /* filename given */
  304.             ext_chg=2;      /* change filename */
  305.             strcpybuff(ext,r.cdispo);
  306.           }
  307.           else if (!may_unknown(r.contenttype) || ishtest == -2) {  // on peut patcher ‡ priori?
  308.             give_mimext(s,r.contenttype);  // obtenir extension
  309.             if (strnotempty(s)>0) {        // on a reconnu l'extension
  310.               ext_chg=1;
  311.               strcpybuff(ext,s);
  312.             }
  313.           }
  314.           //
  315.         } else {          // test imposible dans le cache, faire une requÍte
  316.           //
  317. #if HTS_ANALYSTE
  318.           int hihp=_hts_in_html_parsing;
  319. #endif
  320.           int has_been_moved=0;
  321.           char curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2];
  322.           curr_adr[0]=curr_fil[0]='\0';
  323. #if HTS_ANALYSTE
  324.           _hts_in_html_parsing=2;  // test
  325. #endif
  326.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  327.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete);
  328.             test_flush;
  329.           }
  330.           strcpybuff(curr_adr,adr_complete);
  331.           strcpybuff(curr_fil,fil_complete);
  332.           // ajouter dans le backing le fichier en mode test
  333.           // savename: rien car en mode test
  334.           if (back_add(back,back_max,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1,NULL)!=-1) {
  335.             int b;
  336.             b=back_index(back,back_max,curr_adr,curr_fil,BACK_ADD_TEST);         
  337.             if (b>=0) {
  338.               int petits_tours=0;
  339.               int get_test_request=0;       // en cas de bouclage sur soi mÍme avec HEAD, tester avec GET.. parfois c'est la cause des problËmes
  340.               do {
  341.                 // temps ‡ attendre, et remplir autant que l'on peut le cache (backing)
  342.                 if (back[b].status>0) back_wait(back,back_max,opt,cache,0);        
  343.                 if (ptr>=0)
  344.                   back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  345.   
  346.                 // on est obligÈ d'appeler le shell pour le refresh..
  347. #if HTS_ANALYSTE
  348.                 {
  349.                   
  350.                   // Transfer rate
  351.                   engine_stats();
  352.                   
  353.                   // Refresh various stats
  354.                   HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  355.                   HTS_STAT.stat_errors=fspc(NULL,"error");
  356.                   HTS_STAT.stat_warnings=fspc(NULL,"warning");
  357.                   HTS_STAT.stat_infos=fspc(NULL,"info");
  358.                   HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  359.                   HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  360.  
  361.                   if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  362.                     return -1;
  363.                   } else if (_hts_cancel) {    // cancel 2 ou 1 (cancel parsing)
  364.                     back_delete(back,b);       // cancel test
  365.                   }
  366.                 }
  367. #endif
  368.                 
  369.                 
  370.                 // traitement des 304,303..
  371.                 if (back[b].status<=0) {
  372.                   if (    (back[b].r.statuscode==301)
  373.                        || (back[b].r.statuscode==302)
  374.                        || (back[b].r.statuscode==303)
  375.                        || (back[b].r.statuscode==307)
  376.                      ) {    // agh moved.. un tit tour de plus
  377.                     if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus!
  378.                       if ((int) strnotempty(back[b].r.location)) {    // location existe!
  379.                         char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  380.                         mov_url[0]=mov_adr[0]=mov_fil[0]='\0';
  381.                         //
  382.                         strcpybuff(mov_url,back[b].r.location);    // copier URL
  383.                         if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) {                        
  384.                           // si non bouclage sur soi mÍme, ou si test avec GET non testÈ
  385.                           if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) {
  386.                             // bouclage?
  387.                             if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil)))
  388.                               get_test_request=1;     // faire requËte avec GET
  389.  
  390.                             // recopier former_adr/fil?
  391.                             if ((former_adr) && (former_fil)) {
  392.                               if (strnotempty(former_adr)==0) {    // Pas dÈja notÈ
  393.                                 strcpybuff(former_adr,curr_adr);
  394.                                 strcpybuff(former_fil,curr_fil);
  395.                               }
  396.                             }
  397.  
  398.                             // check explicit forbidden - don't follow 3xx in this case
  399.                             {
  400.                               int set_prio_to=0;
  401.                               robots_wizard* robots = (robots_wizard*) opt->robotsptr;
  402.                               if (hts_acceptlink(opt,ptr,lien_tot,liens,
  403.                                 mov_adr,mov_fil,
  404.                                 opt->filters.filters,opt->filters.filptr,opt->maxfilter,
  405.                                 robots,
  406.                                 &set_prio_to,
  407.                                 NULL) == 1) 
  408.                               {  /* forbidden */
  409.                                 has_been_moved = 1;
  410.                                 back_delete(back,b);    // ok
  411.                                 strcpybuff(curr_adr,mov_adr);
  412.                                 strcpybuff(curr_fil,mov_fil);
  413.                                 mov_url[0]='\0';
  414.                               }
  415.                             }
  416.                             
  417.                             // ftp: stop!
  418.                             if (strfield(mov_url,"ftp://")) {    // ftp, ok on arrÍte
  419.                               has_been_moved = 1;
  420.                               back_delete(back,b);    // ok
  421.                               strcpybuff(curr_adr,mov_adr);
  422.                               strcpybuff(curr_fil,mov_fil);
  423.                             } else if (*mov_url) {
  424.                               char* methode;
  425.                               if (!get_test_request)
  426.                                 methode=BACK_ADD_TEST;      // tester avec HEAD
  427.                               else {
  428.                                 methode=BACK_ADD_TEST2;     // tester avec GET
  429.                                 if ( opt->errlog!=NULL ) {
  430.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil);
  431.                                   test_flush;
  432.                                 }                    
  433.                               }
  434.                               // Ajouter
  435.                               if (back_add(back,back_max,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1,NULL)!=-1) {    // OK
  436.                                 if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  437.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  438.                                   test_flush;
  439.                                 }
  440.                                 
  441.                                 // libÈrer emplacement backing actuel et attendre le prochain
  442.                                 back_delete(back,b);
  443.                                 strcpybuff(curr_adr,mov_adr);
  444.                                 strcpybuff(curr_fil,mov_fil);
  445.                                 b=back_index(back,back_max,curr_adr,curr_fil,methode);         
  446.                                 if (!get_test_request)
  447.                                   has_been_moved = 1;       // sinon ne pas forcer has_been_moved car non dÈplacÈ
  448.                                 petits_tours++;
  449.                                 //
  450.                               } else {// sinon on fait rien et on s'en va.. (ftp etc)
  451.                                 if ( (opt->debug>1)  && (opt->errlog)) {
  452.                                   fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil);
  453.                                   test_flush;
  454.                                 } 
  455.                               }
  456.                             }
  457.                           } else {
  458.                             if ( opt->errlog!=NULL ) {
  459.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete);
  460.                               test_flush;
  461.                             }
  462.                           }
  463.                           
  464.                         }
  465.                       }
  466.                     } else{  // arrÍter les frais
  467.                       if ( opt->errlog!=NULL ) {
  468.                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete);
  469.                         test_flush;
  470.                       }
  471.                     }
  472.                   }  // ok, leaving
  473.                 }
  474.                 
  475.               } while(back[b].status>0);
  476.               
  477.               // Si non dÈplacÈ, forcer type?
  478.               if (!has_been_moved) {
  479.                 if (back[b].r.statuscode!=-10) {    // erreur
  480.                   if (strnotempty(back[b].r.contenttype)==0)
  481.                     strcpybuff(back[b].r.contenttype,"text/html");    // message d'erreur en html
  482.                   // Finalement on, renvoie un erreur, pour ne toucher ‡ rien dans le code
  483.                   // libÈrer emplacement backing
  484.                   /*if (opt->errlog!=NULL) {
  485.                     fspc(opt->errlog,0); fprintf(opt->errlog,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  486.                     test_flush;
  487.                   }                    
  488.                   back_delete(back,b);
  489.                   return -1;        // ERREUR (404 par exemple)
  490.                   */
  491.                 } 
  492.                 
  493.                 {            // pas d'erreur, changer type?
  494.                   char s[16];
  495.                   s[0]='\0';
  496.                   if (strnotempty(back[b].r.cdispo)) {        /* filename given */
  497.                     ext_chg=2;      /* change filename */
  498.                     strcpybuff(ext,back[b].r.cdispo);
  499.                   }
  500.                   else if (!may_unknown(back[b].r.contenttype) || ishtest == -2 ) {  // on peut patcher ‡ priori? (pas interdit ou pas de type)
  501.                     give_mimext(s,back[b].r.contenttype);  // obtenir extension
  502.                     if (strnotempty(s)>0) {    // on a reconnu l'extension
  503.                       ext_chg=1;
  504.                       strcpybuff(ext,s);
  505.                     }
  506.                   }
  507.                 }
  508.               }
  509.               // FIN Si non dÈplacÈ, forcer type?
  510.  
  511.               // libÈrer emplacement backing
  512.               back_delete(back,b);
  513.               
  514.               // --- --- ---
  515.               // oops, a ÈtÈ dÈplacÈ.. on recalcule en rÈcursif (osons!)
  516.               if (has_been_moved) {
  517.                 // copier adr, fil (optionnel, mais sinon marche pas pour le rip)
  518.                 strcpybuff(adr_complete,curr_adr);
  519.                 strcpybuff(fil_complete,curr_fil);
  520.                 // copier adr, fil
  521.                 
  522.                 return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe);
  523.               }
  524.               // --- --- ---
  525.               
  526.             }
  527.             
  528.           } else {
  529.             printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  530. #if BDEBUG==1
  531.             printf("error while savename crash adding\n");
  532. #endif
  533.             if (opt->errlog) {
  534.               fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected savename backing error at %s%s"LF,adr,fil_complete);
  535.               test_flush;
  536.             } 
  537.             
  538.           }
  539.           // restaurer
  540. #if HTS_ANALYSTE
  541.           _hts_in_html_parsing=hihp;
  542. #endif
  543.         }  // cachÈ?
  544.       }
  545.     }
  546.   }
  547.  
  548.  
  549.  
  550.   // - - - DEBUT NOMMAGE - - -
  551.  
  552.   // Donner nom par dÈfaut?
  553.   if (fil[strlen(fil)-1]=='/')  {
  554.     if (!strfield(adr_complete,"ftp://"))
  555.       strcatbuff(fil,DEFAULT_HTML);     // nommer page par dÈfaut!!
  556.     else {
  557.       if (!opt->proxy.active)
  558.         strcatbuff(fil,DEFAULT_FTP);     // nommer page par dÈfaut (texte)
  559.       else
  560.         strcatbuff(fil,DEFAULT_HTML);     // nommer page par dÈfaut (‡ priori ici html depuis un proxy http)
  561.     }
  562.   }
  563.   // Changer extension?
  564.   // par exemple, php3 sera sauvÈ en html, cgi en html ou gif, xbm etc.. selon les cas
  565.   if (ext_chg) {  // changer ext
  566.     char* a=fil+strlen(fil)-1;
  567.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  568.       fspc(opt->log,"debug");
  569.       if (ext_chg==1)
  570.         fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext);
  571.       else
  572.         fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext);
  573.       test_flush;
  574.     }
  575.     if (ext_chg==1) {
  576.       while((a > fil) && (*a!='.') && (*a!='/')) a--;
  577.       if (*a=='.') *a='\0';  // couper
  578.       strcatbuff(fil,".");      // recopier point
  579.     } else {
  580.       while(( a > fil) && (*a!='/')) a--;
  581.       if (*a=='/') a++;
  582.       *a='\0';
  583.    }
  584.     strcatbuff(fil,ext);    // copier ext/nom
  585.   }
  586.  
  587.   // Rechercher premier / et dernier .
  588.   {  
  589.     char* a=fil+strlen(fil)-1;
  590.  
  591.     // passer structures
  592.     start_pos=fil;
  593.     while(( a > fil) && (*a != '/') && (*a != '\\')) {
  594.       if (*a == '.')    // point? noter position
  595.         if (!dot_pos)
  596.           dot_pos=a;
  597.         a--;
  598.     }
  599.     if ((*a=='/') || (*a=='\\')) a++;
  600.     nom_pos = a;
  601.   }
  602.  
  603.   
  604.   // un nom de fichier est gÈnÈrÈ
  605.   // s'il existe dÈja, alors on le mofifie lÈgËrement
  606.  
  607.   // ajouter nom du site Èventuellement en premier
  608.   if (opt->savename_type == -1) {    // utiliser savename_userdef! (%h%p/%n%q.%t)
  609.     char* a = opt->savename_userdef;
  610.     char* b = save;
  611.     /*char *nom_pos=NULL,*dot_pos=NULL;  // Position nom et point */
  612.     char tok;
  613.  
  614.     /*
  615.     {  // Rechercher premier /
  616.       char* a=fil+strlen(fil)-1;
  617.       // passer structures
  618.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  619.         if (*a == '.')    // point? noter position
  620.         if (!dot_pos)
  621.           dot_pos=a;
  622.         a--;
  623.       }
  624.       if ((*a=='/') || (*a=='\\')) a++;
  625.       nom_pos = a;
  626.     }
  627.     */
  628.  
  629.     // Construire nom
  630.     while ((*a) && (((int) (b - save)) < HTS_URLMAXSIZE ) ) {    // parser, et pas trop long..
  631.       if (*a == '%') {
  632.         int short_ver=0;
  633.         a++;
  634.         if (*a == 's') {
  635.           short_ver=1;
  636.           a++;
  637.         }
  638.         *b='\0';
  639.         switch(tok=*a++) {
  640.           case '[':            // %[param]
  641.             if (strchr(a,']')) {
  642.               char name[256];
  643.               char* c=name;
  644.               while(*a!=']') {
  645.                 *c++=*a++;
  646.               }
  647.               a++;
  648.               *c++='\0';
  649.               strcatbuff(name,"=");           /* param=.. */
  650.               c=strchr(fil_complete,'?');
  651.               /* parameters exists */
  652.               if (c) {
  653.                 c=strstr(c,name);     /* finds param= */
  654.                 if (c) {
  655.                   c+=strlen(name);    /* jumps "param=" */
  656.                   while( (*c) && (*c!='&'))
  657.                     *b++=*c++;
  658.                 }
  659.               }
  660.             }
  661.           break;
  662.           case '%': *b++='%'; break;
  663.           case 'n':    // nom sans ext
  664.             if (dot_pos) {
  665.               if (!short_ver)    // Noms longs
  666.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  667.               else
  668.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  669.             } else {
  670.               if (!short_ver)    // Noms longs
  671.                 strcpybuff(b,nom_pos);
  672.               else
  673.                 strncatbuff(b,nom_pos,8);
  674.             }
  675.             b+=strlen(b);   // pointer ‡ la fin
  676.             break;
  677.           case 'N':    // nom avec ext
  678.             // RECOPIE NOM + EXT
  679.             *b='\0';
  680.             if (dot_pos) {
  681.               if (!short_ver)    // Noms longs
  682.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  683.               else
  684.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  685.             } else {
  686.               if (!short_ver)    // Noms longs
  687.                 strcpybuff(b,nom_pos);
  688.               else
  689.                 strncatbuff(b,nom_pos,8);
  690.             }
  691.             b+=strlen(b);   // pointer ‡ la fin
  692.             // RECOPIE NOM + EXT
  693.             *b='\0';
  694.             if (dot_pos) {
  695.               if (!short_ver)    // Noms longs
  696.                 strcpybuff(b,dot_pos+1);
  697.               else
  698.                 strncatbuff(b,dot_pos+1,3);
  699.             } else {
  700.               if (!short_ver)    // Noms longs
  701.                 strcpybuff(b,DEFAULT_EXT);    // pas de..
  702.               else
  703.                 strcpybuff(b,DEFAULT_EXT_SHORT);    // pas de..
  704.             }
  705.             b+=strlen(b);   // pointer ‡ la fin
  706.             //
  707.             break;
  708.           case 't':    // ext
  709.             *b='\0';
  710.             if (dot_pos) {
  711.               if (!short_ver)    // Noms longs
  712.                 strcpybuff(b,dot_pos+1);
  713.               else
  714.                 strncatbuff(b,dot_pos+1,3);
  715.             } else {
  716.               if (!short_ver)    // Noms longs
  717.                 strcpybuff(b,DEFAULT_EXT);    // pas de..
  718.               else
  719.                 strcpybuff(b,DEFAULT_EXT_SHORT);    // pas de..
  720.             }
  721.             b+=strlen(b);   // pointer ‡ la fin
  722.             break;
  723.           case 'p':    // path sans dernier /
  724.             *b='\0';
  725.             if (nom_pos != fil + 1) { // pas: /index.html (chemin nul)
  726.               if (!short_ver) {   // Noms longs
  727.                 strncatbuff(b,fil,(int) (nom_pos - fil) - 1);
  728.               } else {
  729.                 char pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2];
  730.                 pth[0]=n83[0]='\0';
  731.                 //
  732.                 strncatbuff(pth,fil,(int) (nom_pos - fil) - 1);
  733.                 long_to_83(opt->savename_83,n83,pth);
  734.                 strcpybuff(b,n83);
  735.               }
  736.             }
  737.             b+=strlen(b);   // pointer ‡ la fin
  738.             break;
  739.           case 'h':    // host
  740.             *b='\0';
  741.             if (strcmp(adr_complete,"file://")==0) {
  742.               if (!short_ver)    // Noms longs
  743.                 strcpybuff(b,"localhost");
  744.               else
  745.                 strcpybuff(b,"local");
  746.             } else {
  747.               if (!short_ver)    // Noms longs
  748.                 strcpybuff(b,print_adr);
  749.               else
  750.                 strncatbuff(b,print_adr,8);
  751.             }
  752.             b+=strlen(b);   // pointer ‡ la fin
  753.             break;
  754.           case 'M':         /* host/address?query MD5 (128-bits) */
  755.             *b='\0';
  756.             {
  757.               char digest[32+2];
  758.               char buff[HTS_URLMAXSIZE*2];
  759.               digest[0]=buff[0]='\0';
  760.               strcpybuff(buff,adr);
  761.               strcatbuff(buff,fil_complete);
  762.               domd5mem(buff,strlen(buff),digest,1);
  763.               strcpybuff(b,digest);
  764.             }
  765.             b+=strlen(b);   // pointer ‡ la fin
  766.             break;
  767.           case 'Q': case 'q':         /* query MD5 (128-bits/16-bits) 
  768.                                          GENERATED ONLY IF query string exists! */
  769.             *b='\0';
  770.             strncatbuff(b,url_md5(fil_complete),(tok == 'Q')?32:4);
  771.             b+=strlen(b);   // pointer ‡ la fin
  772.             break;
  773.         }
  774.       } else
  775.         *b++=*a++;
  776.     }
  777.     *b++='\0';
  778.     //
  779.     // Types prÈdÈfinis
  780.     //
  781.  
  782.   } 
  783.   //
  784.   // Structure originale
  785.   else if (opt->savename_type%100==0) { 
  786.     /* recopier www.. */
  787.     if (opt->savename_type!=100) {  
  788.       if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  789.         if (strcmp(adr_complete,"file://")==0) {
  790.           //## if (*adr==lOCAL_CHAR) {
  791.           if (opt->savename_83 != 1)  // noms longs
  792.             strcatbuff(save,"localhost");
  793.           else
  794.             strcatbuff(save,"local");
  795.         } else {
  796.           // adresse url
  797.           if (!opt->savename_83) {  // noms longs (et pas de .)
  798.             strcatbuff(save,print_adr);
  799.           } else {  // noms 8-3
  800.             if (strlen(print_adr)>4) {
  801.               if (strfield(print_adr,"www."))
  802.                 strncatbuff(save,print_adr+4,max_char);
  803.               else
  804.                 strncatbuff(save,print_adr,8);
  805.             } else strncatbuff(save,print_adr,max_char);
  806.           }
  807.         }
  808.         if (*fil!='/') strcatbuff(save,"/");
  809.       }
  810.     }
  811.   
  812. #if HTS_CASSE==0
  813.     hts_lowcase(save);
  814. #endif  
  815.         
  816.     /*
  817.     // ne sert ‡ rien car a dÈja ÈtÈ filtrÈ normalement
  818.     if ((*fil=='.') && (*(fil+1)=='/'))          // ./index.html ** //
  819.       url_savename_addstr(save,fil+2);
  820.     else                                               // index.html ou /index.html
  821.       url_savename_addstr(save,fil);
  822.     if (save[strlen(save)-1]=='/') 
  823.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dÈfaut!!
  824. */
  825.  
  826.     /* add name */
  827.     ADD_STANDARD_PATH;
  828.     ADD_STANDARD_NAME(0);
  829.  
  830.   }
  831.   //
  832.   // Structure html/image
  833.   else {    
  834.     // dossier "web" ou "www.xxx" ?
  835.     if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  836.       if ((opt->savename_type/100)%2) {
  837.         if (strcmp(adr_complete,"file://")==0) {
  838.         //## if (*adr==lOCAL_CHAR) {
  839.           if (opt->savename_83 != 1)  // noms longs
  840.             strcatbuff(save,"localhost/");
  841.           else
  842.             strcatbuff(save,"local/");
  843.         } else {
  844.           // adresse url
  845.           if (!opt->savename_83) {  // noms longs
  846.             strcatbuff(save,print_adr); strcatbuff(save,"/");
  847.           } else {  // noms 8-3
  848.             if (strlen(print_adr)>4) {
  849.               if (strfield(print_adr,"www."))
  850.                 strncatbuff(save,print_adr+4,max_char);
  851.               else
  852.                 strncatbuff(save,print_adr,max_char);
  853.               strcatbuff(save,"/");
  854.             } else { 
  855.               strncatbuff(save,print_adr,max_char); strcatbuff(save,"/");
  856.             }
  857.           }
  858.         }
  859.       } else {
  860.         strcatbuff(save,"web/");    // rÈpertoire gÈnÈral
  861.       }
  862.     } 
  863.  
  864.     // si un html ‡ coup s˚r
  865.     if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  866.       if (opt->savename_type%100==2) {  // html/
  867.         strcatbuff(save,"html/");
  868.       }
  869.     } else {
  870.       if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) {  // html & images
  871.         strcatbuff(save,"images/");
  872.       }
  873.     }
  874.     
  875.     switch (opt->savename_type%100) {
  876.     case 4: case 5: {           // sÈparer par types
  877.       char* a=fil+strlen(fil)-1;
  878.       // passer structures
  879.       while(( a > fil) && (*a != '/') && (*a != '\\')) a--;      
  880.       if ((*a=='/') || (*a=='\\')) a++;
  881.  
  882.       // html?
  883.       if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  884.         if (opt->savename_type%100==5)
  885.           strcatbuff(save,"html/");
  886.       } else {
  887.         char* a=fil+strlen(fil)-1;
  888.         while(( a> fil) && (*a != '/') && (*a != '.')) a--;      
  889.         if (*a!='.')
  890.           strcatbuff(save,"other");
  891.         else
  892.           strcatbuff(save,a+1);
  893.         strcatbuff(save,"/");
  894.       }
  895.       /*strcatbuff(save,a);*/
  896.       /* add name */
  897.       ADD_STANDARD_NAME(0);
  898.             }
  899.       break;
  900.     case 99: {                  // 'codÈ' .. c'est un gadget
  901.       int i;
  902.       int j;
  903.       char* a;
  904.       char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
  905.       int L;
  906.       // pseudo-CRC sur fil et adr pour initialiser gÈnÈrateur alÈatoire..
  907.       unsigned int s=0;
  908.       L=strlen(C);
  909.       for(i=0;i<(int) strlen(fil_complete);i++) {
  910.         s+=(unsigned int) fil_complete[i];
  911.       }
  912.       for(i=0;i<(int) strlen(adr_complete);i++) {
  913.         s+=(unsigned int) adr_complete[i];
  914.       }
  915.       srand(s);
  916.       
  917.       j=strlen(save);
  918.       for(i=0;i<8;i++) {
  919.         char c=C[(rand()%L)];
  920.         save[i+j]=c;
  921.       }
  922.       save[i+j]='\0';
  923.       // ajouter extension
  924.       a=fil+strlen(fil)-1;
  925.       while(( a > fil) && (*a != '/') && (*a != '.')) a--;
  926.       if (*a=='.') {
  927.         strcatbuff(save,a);    // ajouter
  928.       }
  929.              } 
  930.       break;
  931.     default: {   // noms sans les noms des rÈpertoires
  932.       // ne garder que le nom, pas la structure
  933.       /*
  934.       char* a=fil+strlen(fil)-1;
  935.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  936.       if ((*a=='/') || (*a=='\\')) a++;
  937.       strcatbuff(save,a);
  938.       */
  939.  
  940.       /* add name */
  941.       ADD_STANDARD_NAME(0);
  942.             }
  943.       break;
  944.     }
  945.  
  946. #if HTS_CASSE==0
  947.     hts_lowcase(save);
  948. #endif  
  949.  
  950.     if (save[strlen(save)-1]=='/') 
  951.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dÈfaut!!
  952.   }
  953.  
  954.  
  955.   // vÈrifier qu'on ne doit pas forcer l'extension
  956.   // par exemple, asp sera sauvÈ en html, cgi en html ou gif, xbm etc.. selon les cas
  957.   /*if (ext_chg) {
  958.     char* a=save+strlen(save)-1;
  959.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  960.     if (*a=='.') *a='\0';  // couper
  961.     // recopier extension
  962.     strcatbuff(save,".");
  963.     strcatbuff(save,ext);    // copier ext
  964.   }*/
  965.   // de mÍme en cas de manque d'extension on en place une de maniËre forcÈe..
  966.   // cela Èvite les /chez/toto et les /chez/toto/index.html incompatibles
  967.   if (opt->savename_type != -1) {
  968.     char* a=save+strlen(save)-1;
  969.     while(( a > save) && (*a!='.') && (*a!='/')) a--;
  970.     if (*a!='.') {   // agh pas de point
  971.       //strcatbuff(save,".none");                 // a Èviter
  972.       strcatbuff(save,".html");                   // prÈfÈrable!
  973.       if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  974.         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Default HTML type set for %s%s"LF,adr_complete,fil_complete);
  975.         test_flush;
  976.       }
  977.     }
  978.   }
  979.  
  980.   // effacer pass au besoin pour les autentifications
  981.   // (plus la peine : masquÈ au dÈbut)
  982. /*
  983.   {
  984.     char* a=jump_identification(save);
  985.     if (a!=save) {
  986.       char tempo[HTS_URLMAXSIZE*2];
  987.       char *b;
  988.       tempo[0]='\0';
  989.       strcpybuff(tempo,"[");
  990.       b=strchr(save,':');
  991.       if (!b) b=strchr(save,'@');
  992.       if (b)
  993.         strncatbuff(tempo,save,(int) b-(int) a);
  994.       strcatbuff(tempo,"]");
  995.       strcatbuff(tempo,a);
  996.       strcpybuff(save,a);
  997.     }
  998.   }
  999. */
  1000.  
  1001.   // Èviter les / au dÈbut (cause: N100)
  1002.   if (save[0]=='/') {
  1003.     char tempo[HTS_URLMAXSIZE*2];
  1004.     strcpybuff(tempo,save+1);
  1005.     strcpybuff(save,tempo);
  1006.   }
  1007.  
  1008.   // changer les ~,:,",*,? en _ pour sauver sur disque
  1009.   hts_replace(save,'~','_');  // interdit sous unix (~foo)
  1010.   //
  1011.   hts_replace(save,'\\','_');
  1012.   hts_replace(save,':','_');  // interdit sous windows
  1013.   hts_replace(save,'*','_');  // interdit sous windows
  1014.   hts_replace(save,'?','_');  // doit pas arriver!!
  1015.   hts_replace(save,'\"','_');  // interdit sous windows
  1016.   hts_replace(save,'<','_');  // interdit sous windows
  1017.   hts_replace(save,'>','_');  // interdit sous windows
  1018.   hts_replace(save,'|','_');  // interdit sous windows
  1019.   //
  1020.   hts_replace(save,'@','_');
  1021.   //
  1022.   { // Èliminer les // (comme ftp://)
  1023.     char* a;
  1024.     while( (a=strstr(save,"//")) ) *a='_';
  1025.     // Eliminer chars spÈciaux
  1026.     a=save -1 ;
  1027.     while(*(++a))
  1028.       if ( ((unsigned char)(*a) <= 31)
  1029.           || ((unsigned char)(*a) == 127) )
  1030.         *a='_';
  1031.   }
  1032.  
  1033.    
  1034. #if HTS_OVERRIDE_DOS_FOLDERS
  1035.   /* Replace /foo/nul/bar by /foo/nul-/bar */
  1036.   {
  1037.     int i=0;
  1038.     while(hts_tbdev[i][0]) {
  1039.       char* a=save;
  1040.       while((a=strstr(a,hts_tbdev[i]))) {
  1041.         switch ( (int) a[strlen(hts_tbdev[i])] ) {
  1042.         case '\0':
  1043.         case '/':  {
  1044.           char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0';
  1045.           strncatbuff(tempo,save,(int) (a - save) + strlen(hts_tbdev[i]));
  1046.           strcatbuff(tempo,"-");
  1047.           strcatbuff(tempo,a+strlen(hts_tbdev[i]));
  1048.           strcpybuff(save,tempo);
  1049.                    }
  1050.           break;
  1051.         }
  1052.         a+=strlen(hts_tbdev[i]);
  1053.       }
  1054.       i++;
  1055.     }
  1056.   }
  1057. #endif
  1058.  
  1059.   // conversion 8-3 .. y compris pour les rÈpertoires
  1060.   if (opt->savename_83) {
  1061.     char n83[HTS_URLMAXSIZE*2];
  1062.     long_to_83(opt->savename_83,n83,save);
  1063.     strcpybuff(save,n83);
  1064.   }
  1065.  
  1066.  
  1067.   /* ensure that there is no ../ (potential vulnerability) */
  1068.   fil_simplifie(save);
  1069.  
  1070. #if HTS_ANALYSTE
  1071.   {
  1072.     hts_htmlcheck_savename(adr_complete,fil_complete,referer_adr,referer_fil,save);
  1073.     if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1074.       fspc(opt->log,"info"); fprintf(opt->log,"engine: save-name: local name: %s%s -> %s"LF,adr,fil,save);
  1075.       test_flush;
  1076.     }
  1077.   }
  1078. #endif
  1079.  
  1080.   // chemin primaire Èventuel A METTRE AVANT
  1081.   if (strnotempty(opt->path_html)) {
  1082.     char tempo[HTS_URLMAXSIZE*2];
  1083.     strcpybuff(tempo,opt->path_html);
  1084.     strcatbuff(tempo,save);
  1085.     strcpybuff(save,tempo);
  1086.   }
  1087.  
  1088.  
  1089.   // vÈrifier que le nom n'est pas dÈja pris...
  1090.   if (liens!=NULL) { 
  1091.     int nom_ok;
  1092.     do {
  1093.       int i;
  1094.       int len;
  1095.       len=strlen(save);    // taille
  1096.       //
  1097.       nom_ok=1;  // ‡ priori bon
  1098.       // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite..
  1099. #if DEBUG_SAVENAME
  1100. printf("\nStart search\n");
  1101. #endif
  1102.  
  1103. #if HTS_HASH
  1104.       i=hash_read(hash,save,"",0);      // lecture type 0 (sav)
  1105.       if (i>=0)
  1106. #else
  1107.       for(i=lien_tot-1;i>=0;i--) {
  1108. #if DEBUG_SAVENAME
  1109. printf("%cParse: %d",13,i);
  1110. #endif
  1111.         
  1112.         if (liens[i]->sav_len==len) {    // mÍme taille de chaÓne          
  1113. #if HTS_CASSE
  1114.           if (strcmp(liens[i]->sav,save)==0)    // existe dÈja
  1115. #else
  1116.           if (strfield2(liens[i]->sav,save))    // un tel nom existe dÈja
  1117. #endif
  1118. #endif
  1119.           {
  1120. #if HTS_CASSE
  1121.             if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  1122. #else
  1123.             if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  1124. #endif
  1125.             {    // ok c'est le mÍme lien, adresse dÈja dÈfinie
  1126.               //printf("Ok, %s\n",save);
  1127.               //i=lien_tot;    // sortir
  1128.               i=0;
  1129. #if DEBUG_SAVENAME
  1130. printf("\nOK ALREADY DEFINED\n",13,i);
  1131. #endif
  1132.             } else {  // utilisÈ par un AUTRE, changer de nom
  1133.               char tempo[HTS_URLMAXSIZE*2];
  1134.               char* a=save+strlen(save)-1;
  1135.               char* b;
  1136.               int n=2;       
  1137.               tempo[0]='\0';
  1138.  
  1139. #if DEBUG_SAVENAME
  1140. printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete);
  1141. #endif
  1142.               nom_ok=0;
  1143.               i=0;
  1144.               
  1145.               while(( a > save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--;
  1146.               if (*a=='.')
  1147.                 strncatbuff(tempo,save,(int) (a - save));
  1148.               else
  1149.                 strcatbuff(tempo,save);
  1150.               
  1151.               // tester la prÈsence d'un -xx (ex: index-2.html -> index-3.html)
  1152.               b=tempo+strlen(tempo)-1;
  1153.               while (isdigit((unsigned char)*b)) b--;
  1154.               if (*b=='-') {
  1155.                 sscanf(b+1,"%d",&n);
  1156.                 *b='\0';    // couper
  1157.                 n++;  // plus un
  1158.               }
  1159.               
  1160.               // en plus il faut gÈrer le 8-3 .. pas facile le client
  1161.               if (opt->savename_83) {
  1162.                 int max;
  1163.                 char* a=tempo+strlen(tempo)-1;
  1164.                 while(( a > tempo) && (*a!='/')) a--;
  1165.                 if (*a=='/') a++;
  1166.                 max=max_char-1-nombre_digit(n);
  1167.                 if ((int) strlen(a)>max)
  1168.                   *(a+max)='\0';  // couper sinon il n'y aura pas la place!
  1169.               }
  1170.               
  1171.               // ajouter -xx (ex: index.html -> index-2.html)
  1172.               sprintf(tempo+strlen(tempo),"-%d",n);
  1173.               
  1174.               // ajouter extension
  1175.               if (*a=='.')
  1176.                 strcatbuff(tempo,a);
  1177.               
  1178.               strcpybuff(save,tempo);
  1179.               
  1180.               //printf("switched: %s\n",save);
  1181.               
  1182.             }  // if
  1183. #if HTS_HASH
  1184.           }
  1185. #else
  1186.           }  // if
  1187.         }  // if sav_len
  1188.       }  // for
  1189. #endif
  1190. #if DEBUG_SAVENAME
  1191. printf("\nEnd search, %s\n",fil_complete);
  1192. #endif
  1193.     } while(!nom_ok);
  1194.     
  1195.   }
  1196.   
  1197.   //printf("'%s' %s %s\n",save,adr,fil);
  1198.       
  1199.   return 0;
  1200. }
  1201.  
  1202. /* nom avec md5 urilisÈ partout */
  1203. void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) {
  1204.   b[0]='\0';
  1205.   /* Nom */
  1206.   if (dot_pos) {
  1207.     if (!short_ver)    // Noms longs
  1208.       strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  1209.     else
  1210.       strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  1211.   } else {
  1212.     if (!short_ver)    // Noms longs
  1213.       strcatbuff(b,nom_pos);
  1214.     else
  1215.       strncatbuff(b,nom_pos,8);
  1216.   }
  1217.   /* MD5 - 16 bits */
  1218.   strncatbuff(b,url_md5(fil_complete),4);
  1219.   /* Ext */
  1220.   if (dot_pos) {
  1221.     strcatbuff(b,".");
  1222.     if (!short_ver)    // Noms longs
  1223.       strcatbuff(b,dot_pos+1);
  1224.     else
  1225.       strncatbuff(b,dot_pos+1,3);
  1226.   } else {
  1227.     if (!short_ver)    // Noms longs
  1228.       strcatbuff(b,DEFAULT_EXT);    // pas de..
  1229.     else
  1230.       strcatbuff(b,DEFAULT_EXT_SHORT);    // pas de..
  1231.   }
  1232. }
  1233.  
  1234.  
  1235. /* Petit md5 */
  1236. char* url_md5(char* fil_complete) {
  1237.   char* digest;
  1238.   char* a;
  1239.   NOSTATIC_RESERVE(digest, char, 32+2);
  1240.   digest[0]='\0';
  1241.   a=strchr(fil_complete,'?');
  1242.   if (a) {
  1243.     if (strlen(a)) {
  1244.       char buff[HTS_URLMAXSIZE*2];
  1245.       a++;
  1246.       digest[0]=buff[0]='\0';
  1247.       strcatbuff(buff,a);         /* query string MD5 */
  1248.       domd5mem(buff,strlen(buff),digest,1);
  1249.     }
  1250.   }
  1251.   return digest;
  1252. }
  1253.  
  1254. // interne ‡ url_savename: ajoute une chaÓne ‡ une autre avec \ -> /
  1255. void url_savename_addstr(char* d,char* s) {
  1256.   int i=strlen(d);
  1257.   while(*s) {
  1258.     if (*s=='\\')  // remplacer \ par des /
  1259.       d[i++]='/';
  1260.     else
  1261.       d[i++]=*s;
  1262.     s++;
  1263.   }
  1264.   d[i]='\0';
  1265. }
  1266.  
  1267. #undef test_flush
  1268.